/************************************************************************

								Heroes IV
					  Copyright 2000, The 3DO Company

	------------------------------------------------------------------
  						 threat_footprint.cpp

	$Header: /heroes4/threat_footprint.cpp $

	$NoKeywords: $

 ************************************************************************/

// kill the 255+ character identifier warning.  Templates tend to exceed that easily.
#include "precompiled.h"
#pragma warning( disable: 4786 )

#include "threat_footprint.h"

#include <map>
#include "angle.h"
#include "direction.h"
// -------------------------------------------------------------------------
// footprint of combat object, marked by cell as to whether a cell is used.
// -------------------------------------------------------------------------
t_threat_footprint::t_threat_footprint( int size, t_direction direction, int arc )
{
	int		     row;
	int		     column;
	int		     delta_row;
	int		     delta_column;
	int		     delta_row_squared;
	int		     distance;
	int*	     marked;
	t_direction* angles;
	int          size_squared = size * size;
	bool         in_range;
	int          angle;
	int          base_angle;
	t_direction  bearing;

	m_size = size;
	m_arc = arc;
	m_direction = direction;
	base_angle = ::get_angle( direction );
	m_angles.resize( size_squared );
	m_marked.resize( size_squared );
	marked = ((m_marked.size() > 0) ? &(*m_marked.begin()) : NULL);
	angles = ((m_angles.size() > 0) ? &(*m_angles.begin()) : NULL);
	delta_row = 1 - size;
	for (row = 0; row < size; row++)
	{
		delta_row_squared = delta_row * delta_row;
		delta_column = 1 - size;
		for (column = 0; column < size; column++)
		{
			distance = delta_column * delta_column + delta_row_squared;
			in_range = (distance <= size_squared);
			if (in_range && arc < 360)
			{
				angle = ::get_angle( t_map_point_2d( delta_row, delta_column ));
				bearing = ::get_direction( angle );
				angle = get_difference( angle, base_angle );
				if (angle * 2 > arc)
					in_range = false;
			}
			*marked++ = in_range;
			if (in_range)
				*angles++ = bearing;
			else
				*angles++ = k_direction_count;
			delta_column += 2;
		}
		delta_row += 2;
	}
}

namespace 
{
	struct t_key 
	{
		int         size;
		t_direction direction;
		int         arc;

		t_key( int new_size, t_direction new_direction, int new_arc )
		{
			size = new_size;
			direction = new_direction;
			arc = new_arc;
		}

	};
	bool operator < (t_key const& left, t_key const& right )
	{
		if (left.size != right.size )
			return left.size < right.size;
		if (left.direction != right.direction)
			return left.direction < right.direction;
		return left.arc < right.arc;
	}
};


typedef std::map< t_key, t_threat_footprint> t_threat_map;

// -------------------------------------------------------------------------
// get a specific threat footprint
// -------------------------------------------------------------------------
t_threat_footprint const& get_threat_footprint( int size, t_direction direction, int arc )
{
	static t_threat_map    threat_map;
	t_threat_map::iterator result;
	t_key                  key( size, direction, arc );

	result = threat_map.find( key );
	if (result == threat_map.end())
	{
		result = threat_map.insert( std::make_pair( key,
			                        t_threat_footprint( size, direction, arc ))).first;
	}
	return result->second;
}


